package com.ruoyi.system.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.mapper.WarehousingEntryMapper;
import com.ruoyi.system.service.*;
import com.ruoyi.system.util.AbdulEmptyUtils;
import com.ruoyi.system.util.BookingNumberGenerator;
import com.ruoyi.system.util.StoreIdUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 入库单 服务实现类
 *
 * @author ruoyi
 * @date 2025-06-04
 */
@Service
public class WarehousingEntryServiceImpl extends ServiceImpl<WarehousingEntryMapper, WarehousingEntry> implements IWarehousingEntryService {

    @Autowired
    private StoreIdUtils storeIdUtils;

    @Autowired
    private IInventoryDetailsService inventoryDetailsService;

    @Autowired
    private IWarehouseService warehouseService;

    @Autowired
    private IInventoryTransactionService inventoryTransactionService;

    @Autowired
    private IProductInventoryService productInventoryService;

    @Autowired
    private IProductManagementService productManagementService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(WarehousingEntry warehousingEntry) {
        // 入库 1-生成入库单 2-增加入库明细 3-添加到库存表 4-入库明细记录
        //参数效验
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getWarehouseId())) {
            throw new RuntimeException("请选择入库仓库");
        }
        Warehouse warehouse = warehouseService.getById(warehousingEntry.getWarehouseId());
        if (AbdulEmptyUtils.isEmpty(warehouse)) {
            throw new RuntimeException("入库仓库不存在");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getStoreBusinessId())) {
            throw new RuntimeException("请选择入库类型");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getCreateBy())) {
            throw new RuntimeException("请选择入库人");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getInventoryDetails())) {
            throw new RuntimeException("请选择入库商品");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getInOutTime())) {
            throw new RuntimeException("请选择入库时间");
        }
        //初始化公共字段
        Long storeId = storeIdUtils.getStoreId();
        Date now = new Date();
        String entryCode = BookingNumberGenerator.generateBookingNumber();
        warehousingEntry.setIsType(1);
        warehousingEntry.setStoreId(storeId);
        warehousingEntry.setCreateTime(now);
        warehousingEntry.setCode(entryCode);
        this.save(warehousingEntry);  //保存入库单主表

        Long id = warehousingEntry.getId();
        List<InventoryDetails> inventoryDetails = warehousingEntry.getInventoryDetails();
        //设置并效验入库明细
        for (InventoryDetails inventoryDetail : inventoryDetails) {
            if (inventoryDetail.getInboundQuantity() <= 0) {
                throw new RuntimeException("入库数量必须大于0");
            }
            if (AbdulEmptyUtils.isEmpty(inventoryDetail.getInventoryPrice())) {
                throw new RuntimeException("库存单价必须不能为空");
            }
            if (AbdulEmptyUtils.isEmpty(inventoryDetail.getPurchasePrice())) {
                throw new RuntimeException("采购单价必须不能为空");
            }
            if (AbdulEmptyUtils.isEmpty(inventoryDetail.getProductManagementId())) {
                throw new RuntimeException("商品ID不能为空");
            }
            inventoryDetail.setWarehousingEntryId(id);
            inventoryDetail.setStoreId(storeId);
            inventoryDetail.setCreateTime(now);
            inventoryDetail.setCreateBy(warehousingEntry.getCreateBy());
            inventoryDetail.setIsType(1);
        }
        inventoryDetailsService.saveBatch(inventoryDetails); // 保存入库明细

        //查询商品信息构建映射
        Set<Long> productIds = inventoryDetails.stream()
                .map(InventoryDetails::getProductManagementId)
                .filter(java.util.Objects::nonNull)
                .collect(Collectors.toSet());

        LambdaQueryWrapper<ProductManagement> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ProductManagement::getId, productIds);
        List<ProductManagement> productManagements = productManagementService.list(wrapper);

        if (AbdulEmptyUtils.isEmpty(productManagements)) {
            throw new RuntimeException("商品不存在");
        }

        Map<Long, InventoryDetails> detailsMap = inventoryDetails.stream()
                .collect(Collectors.toMap(InventoryDetails::getProductManagementId, e -> e));
        //处理库存新增或更新
        List<ProductInventory> saveList = new ArrayList<>();
        List<ProductInventory> updateList = new ArrayList<>();
        List<InventoryTransaction> logList = new ArrayList<>();

        LambdaQueryWrapper<ProductInventory> lqw = Wrappers.lambdaQuery();

        for (ProductManagement productManagement : productManagements) {
            Long productManagementId = productManagement.getId();
            InventoryDetails details = detailsMap.get(productManagementId);

            lqw.clear();
            lqw.eq(ProductInventory::getProductManagementId, productManagementId);
            lqw.eq(ProductInventory::getWarehouseId, warehouse.getId());
            ProductInventory productInventory = productInventoryService.getOne(lqw);
            //创建库存变动日志
            InventoryTransaction inventoryTransaction = new InventoryTransaction();
            inventoryTransaction.setBeforeQuantity(AbdulEmptyUtils.isEmpty(productInventory) ? 0 : productInventory.getStockQuantity());

            if (AbdulEmptyUtils.isEmpty(productInventory)) {
                long snowflakeId;
                try {
                    snowflakeId = IdUtil.getSnowflake().nextId();
                } catch (Exception e) {
                    throw new RuntimeException("生成库存ID失败", e);
                }

                inventoryTransaction.setProductInventoryId(snowflakeId);

                ProductInventory productInventorySave = new ProductInventory();
                productInventorySave.setId(snowflakeId);
                productInventorySave.setCode(warehousingEntry.getCode());
                productInventorySave.setName(details.getName());
                productInventorySave.setSpecification(details.getSpecification());
                productInventorySave.setCategory(details.getCategory());
                productInventorySave.setClassification(details.getClassification());
                productInventorySave.setProductManagementId(productManagementId);
                productInventorySave.setUnit(details.getUnit());
                productInventorySave.setWarehouseId(warehousingEntry.getWarehouseId());
                productInventorySave.setInStock(productManagement.getParticipateInventory());
                productInventorySave.setMinStock(Math.toIntExact(productManagement.getInventoryWarning()));
                productInventorySave.setMaxStock(Math.toIntExact(productManagement.getInventoryMax()));
                productInventorySave.setStockQuantity(details.getInboundQuantity());

                if (productInventorySave.getStockQuantity() > productInventorySave.getMaxStock()) {
                    productInventorySave.setStockWarning(2);
                } else if (productInventorySave.getStockQuantity() < productInventorySave.getMinStock()) {
                    productInventorySave.setStockWarning(1);
                } else {
                    productInventorySave.setStockWarning(0);
                }

                productInventorySave.setUnitPrice(details.getInventoryPrice());
                productInventorySave.setSellingPrice(productManagement.getSellingPrice());
                productInventorySave.setCreateBy(SecurityUtils.getUsername());
                productInventorySave.setStoreId(storeId);

                saveList.add(productInventorySave);
            } else {
                productInventory.setInStock(productManagement.getParticipateInventory());
                productInventory.setMinStock(Math.toIntExact(productManagement.getInventoryWarning()));
                productInventory.setMaxStock(Math.toIntExact(productManagement.getInventoryMax()));
                productInventory.setStockQuantity(details.getInboundQuantity() + productInventory.getStockQuantity());

                if (productInventory.getStockQuantity() < productInventory.getMinStock()) {
                    productInventory.setStockWarning(1);
                } else if (productInventory.getStockQuantity() > productInventory.getMaxStock()) {
                    productInventory.setStockWarning(2);
                } else {
                    productInventory.setStockWarning(0);
                }

                productInventory.setUnitPrice(details.getInventoryPrice());
                productInventory.setSellingPrice(productManagement.getSellingPrice());
                productInventory.setUpdateBy(SecurityUtils.getUsername());

                updateList.add(productInventory);
                inventoryTransaction.setProductInventoryId(productInventory.getId());
            }
            //  设置库存变动日志字段
            inventoryTransaction.setType(1);
            inventoryTransaction.setStoreBusinessId(warehousingEntry.getStoreBusinessId());
            inventoryTransaction.setInvWarehousingEntryId(id);
            inventoryTransaction.setWarehouseId(warehousingEntry.getWarehouseId());
            inventoryTransaction.setProductName(details.getName());
            inventoryTransaction.setSpecification(details.getSpecification());
            inventoryTransaction.setCategory(details.getCategory());
            inventoryTransaction.setClassification(details.getClassification());
            inventoryTransaction.setCode(warehousingEntry.getCode());
            inventoryTransaction.setUnit(details.getUnit());
            inventoryTransaction.setChangeQuantity(details.getInboundQuantity());
            inventoryTransaction.setUnitPrice(details.getInventoryPrice());

            BigDecimal beforeQty = BigDecimal.valueOf(inventoryTransaction.getBeforeQuantity());
            BigDecimal changeQty = BigDecimal.valueOf(inventoryTransaction.getChangeQuantity());
            BigDecimal unitPrice = Optional.ofNullable(inventoryTransaction.getUnitPrice()).orElse(BigDecimal.ZERO);

            inventoryTransaction.setTotalValue(beforeQty.add(changeQty).multiply(unitPrice).setScale(2, RoundingMode.HALF_UP));
            inventoryTransaction.setCreateBy(SecurityUtils.getUsername());
            inventoryTransaction.setStoreId(storeId);

            logList.add(inventoryTransaction);
        }

        if (!AbdulEmptyUtils.isEmpty(saveList)) {
            productInventoryService.saveBatch(saveList);
        }
        if (!AbdulEmptyUtils.isEmpty(updateList)) {
            productInventoryService.updateBatchById(updateList);
        }
        if (!AbdulEmptyUtils.isEmpty(logList)) {
            inventoryTransactionService.saveBatch(logList);
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean out(WarehousingEntry warehousingEntry) {
        // 出库 1-生成出库单 2-增加出库明细 3-更新库存表 4-记录出库明细日志

        // 1. 参数校验
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getWarehouseId())) {
            throw new RuntimeException("请选择出库仓库");
        }
        Warehouse warehouse = warehouseService.getById(warehousingEntry.getWarehouseId());
        if (AbdulEmptyUtils.isEmpty(warehouse)) {
            throw new RuntimeException("出库仓库不存在");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getStoreBusinessId())) {
            throw new RuntimeException("请选择出库类型");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getCreateBy())) {
            throw new RuntimeException("请选择出库人");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getInventoryDetails())) {
            throw new RuntimeException("请选择出库商品");
        }
        if (AbdulEmptyUtils.isEmpty(warehousingEntry.getInOutTime())) {
            throw new RuntimeException("请选出库时间");
        }
        // 2. 初始化公共字段
        Long storeId = storeIdUtils.getStoreId();
        Date now = new Date();
        String entryCode = BookingNumberGenerator.generateBookingNumber();

        warehousingEntry.setStoreId(storeId);
        warehousingEntry.setIsType(2);
        warehousingEntry.setCreateTime(now);
        warehousingEntry.setCode(entryCode);
        this.save(warehousingEntry); // 保存出库单主表

        Long id = warehousingEntry.getId();
        List<InventoryDetails> inventoryDetails = warehousingEntry.getInventoryDetails();

        // 3. 设置并校验出库明细
        for (InventoryDetails inventoryDetail : inventoryDetails) {
            if (inventoryDetail.getInboundQuantity() <= 0) {
                throw new RuntimeException("出库数量必须大于0");
            }
            if (AbdulEmptyUtils.isEmpty(inventoryDetail.getProductManagementId())) {
                throw new RuntimeException("商品ID不能为空");
            }

            inventoryDetail.setWarehousingEntryId(id);
            inventoryDetail.setStoreId(storeId);
            inventoryDetail.setCreateTime(now);
            inventoryDetail.setIsType(2);
            inventoryDetail.setCreateBy(warehousingEntry.getCreateBy());
        }
        inventoryDetailsService.saveBatch(inventoryDetails); // 批量保存明细

        // 4. 查询商品信息并构建映射
        Set<Long> productIds = inventoryDetails.stream()
                .map(InventoryDetails::getProductManagementId)
                .filter(java.util.Objects::nonNull)
                .collect(Collectors.toSet());

        LambdaQueryWrapper<ProductManagement> wrapper = Wrappers.lambdaQuery();
        wrapper.in(ProductManagement::getId, productIds);
        List<ProductManagement> productManagements = productManagementService.list(wrapper);

        if (AbdulEmptyUtils.isEmpty(productManagements)) {
            throw new RuntimeException("商品不存在");
        }

        Map<Long, InventoryDetails> detailsMap = inventoryDetails.stream()
                .collect(Collectors.toMap(InventoryDetails::getProductManagementId, e -> e));

        // 5. 处理库存更新和日志记录
        List<ProductInventory> updateList = new ArrayList<>();
        List<InventoryTransaction> logList = new ArrayList<>();

        LambdaQueryWrapper<ProductInventory> lqw = Wrappers.lambdaQuery();

        for (ProductManagement productManagement : productManagements) {
            Long productManagementId = productManagement.getId();
            InventoryDetails details = detailsMap.get(productManagementId);

            lqw.clear();
            lqw.eq(ProductInventory::getProductManagementId, productManagementId);
            lqw.eq(ProductInventory::getWarehouseId, warehousingEntry.getWarehouseId());
            ProductInventory productInventory = productInventoryService.getOne(lqw);

            if (AbdulEmptyUtils.isEmpty(productInventory)) {
                throw new RuntimeException("商品【" + details.getName() + "】库存不足，无法出库");
            }

            // 检查库存是否足够
            int outboundQty = details.getInboundQuantity();
            if (productInventory.getStockQuantity() < outboundQty) {
                throw new RuntimeException("商品【" + details.getName() + "】库存不足，当前库存：" + productInventory.getStockQuantity());
            }

            // 6. 更新库存
            productInventory.setStockQuantity(productInventory.getStockQuantity() - outboundQty);
            productInventory.setUpdateBy(SecurityUtils.getUsername());

            // 更新库存预警状态
            if (productInventory.getStockQuantity() < productInventory.getMinStock()) {
                productInventory.setStockWarning(1);
            } else if (productInventory.getStockQuantity() > productInventory.getMaxStock()) {
                productInventory.setStockWarning(2);
            } else {
                productInventory.setStockWarning(0);
            }
            productInventory.setUpdateBy(SecurityUtils.getUsername());
            productInventory.setUpdateTime(new Date());
            updateList.add(productInventory);

            // 7. 创建库存变动日志
            InventoryTransaction inventoryTransaction = new InventoryTransaction();
            inventoryTransaction.setBeforeQuantity(productInventory.getStockQuantity() + outboundQty); // 变动前库存 = 当前 + 出库数量
            inventoryTransaction.setType(2); // 类型：2-出库
            inventoryTransaction.setStoreBusinessId(warehousingEntry.getStoreBusinessId());
            inventoryTransaction.setInvWarehousingEntryId(id);
            inventoryTransaction.setWarehouseId(warehousingEntry.getWarehouseId());
            inventoryTransaction.setProductName(details.getName());
            inventoryTransaction.setSpecification(details.getSpecification());
            inventoryTransaction.setCategory(details.getCategory());
            inventoryTransaction.setClassification(details.getClassification());
            inventoryTransaction.setCode(productInventory.getCode());
            inventoryTransaction.setUnit(details.getUnit());
            inventoryTransaction.setChangeQuantity(outboundQty);
            inventoryTransaction.setUnitPrice(productInventory.getUnitPrice());
            inventoryTransaction.setProductInventoryId(productInventory.getId());
            BigDecimal beforeQty = BigDecimal.valueOf(inventoryTransaction.getBeforeQuantity());
            BigDecimal changeQty = BigDecimal.valueOf(inventoryTransaction.getChangeQuantity());
            BigDecimal unitPrice = Optional.ofNullable(inventoryTransaction.getUnitPrice()).orElse(BigDecimal.ZERO);

            inventoryTransaction.setTotalValue(beforeQty.subtract(changeQty).multiply(unitPrice).setScale(2, RoundingMode.HALF_UP));
            inventoryTransaction.setCreateBy(SecurityUtils.getUsername());
            inventoryTransaction.setStoreId(storeId);

            logList.add(inventoryTransaction);
        }

        // 8. 批量保存更新和日志
        if (!AbdulEmptyUtils.isEmpty(updateList)) {
            productInventoryService.updateBatchById(updateList);
        }
        if (!AbdulEmptyUtils.isEmpty(logList)) {
            inventoryTransactionService.saveBatch(logList);
        }
        return true;
    }

}
